home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c-part2 / 11033 < prev    next >
Encoding:
Text File  |  1996-08-05  |  4.4 KB  |  127 lines

  1. Newsgroups: comp.lang.c
  2. Path: news.sprintlink.net!eskimo!scs
  3. From: scs@eskimo.com (Steve Summit)
  4. Subject: Re: void ** question
  5. X-Nntp-Posting-Host: eskimo.com
  6. Message-ID: <DoML1s.BEC@eskimo.com>
  7. Sender: news@eskimo.com (News User Id)
  8. Organization: schmorganization
  9. References: <DoJBrL.F5t@bear.wn.bawue.de>
  10. Date: Thu, 21 Mar 1996 16:13:04 GMT
  11.  
  12. In article <DoJBrL.F5t@bear.wn.bawue.de>, jo@bear.wn.bawue.de
  13. (Joerg Sommrey) writes:
  14. > I have a question concerning conversion to `void **'.
  15. >...
  16. > On four platforms I get three results: silence, warning and error...
  17. >
  18. > The FAQ states there isn't a portable way of calling a function with a
  19. > generic pointer by reference. This seems to be the point but I do not
  20. > understand why.
  21.  
  22. The book-length version of the FAQ list (ask me for details)
  23. explains at some length:
  24.  
  25. 4.9:    Suppose I want to write a function that takes a generic pointer
  26.     as an argument and I want to simulate passing it by reference.
  27.     Can I give the formal parameter type void **, and do something
  28.     like this?
  29.  
  30.         void f(void **);
  31.         double *dp;
  32.         f((void **)&dp);
  33.  
  34. A:    Not portably.  Code like this may work and is sometimes
  35.     recommended, but it relies on all pointer types having the same
  36.     internal representation (which is common, but not universal; see
  37.     question 5.17).
  38.  
  39.     There is no generic pointer-to-pointer type in C.  void * acts
  40.     as a generic pointer only because conversions are applied
  41.     automatically when other pointer types are assigned to and from
  42.     void *'s; these conversions cannot be performed if an attempt is
  43.     made to indirect upon a void ** value which points at something
  44.     other than a void *.  When you make use of a void ** pointer
  45.     value (for instance, when you use the * operator to access the
  46.     void * value to which the void ** points), the compiler has no
  47.     way of knowing whether that void * value was once converted from
  48.     some other pointer type.  It must assume that it is nothing more
  49.     than a void *; it cannot perform any implicit conversions.
  50.  
  51.     In other words, any void ** value you play with must be the
  52.     address of an actual void * value somewhere; casts like
  53.     (void **)&dp, though they may shut the compiler up, are
  54.     nonportable (and may not even do what you want; see also
  55.     question 13.9).  If the pointer that the void ** points to is
  56.     not a void *, and if it has a different size or representation
  57.     than a void *, then the compiler isn't going to be able to
  58.     access it correctly.
  59.  
  60.     To make the code fragment above work, you'd have to use an
  61.     intermediate void * variable:
  62.  
  63.         double *dp;
  64.         void *vp = dp;
  65.         f(&vp);
  66.         dp = vp;
  67.  
  68.     The assignments to and from vp give the compiler the opportunity
  69.     to perform any conversions, if necessary.
  70.  
  71.     Again, the discussion so far assumes that different pointer
  72.     types might have different sizes or representations, which is
  73.     rare today, but not unheard of.  To appreciate the problem with
  74.     void ** more clearly, compare the situation to an analogous one
  75.     involving, say, types int and double, which probably have
  76.     different sizes and certainly have different representations.
  77.     If we have a function
  78.  
  79.         void incme(double *p)
  80.         {
  81.             *p += 1;
  82.         }
  83.  
  84.     then we can do something like
  85.  
  86.         int i = 1;
  87.         double d = i;
  88.         incme(&d);
  89.         i = d;
  90.  
  91.     and i will be incremented by 1.  (This is analogous to the
  92.     correct void ** code involving the auxiliary vp.)  If, on the
  93.     other hand, we were to attempt something like
  94.  
  95.         int i = 1;
  96.         incme((double *)&i);    /* WRONG */
  97.  
  98.     (this code is analogous to the fragment in the question), it
  99.     would be highly unlikely to work.
  100.  
  101.  
  102. Jo went on to ask:
  103. > My questions:
  104. > 1) Is `(void **) ppi' legal (which makes any tested compiler shut up)?
  105.  
  106. I hope the above discussion shows that it is not.
  107.  
  108. (Also, by the way, I hope that no one objects to these excerpts
  109. I sometimes post as being ads, although of course I'd love it if
  110. y'all bought a copy.)
  111.  
  112. > 3) Are any of these compilers broken?
  113.  
  114. Since it's undefined what happens when you use an explicit cast
  115. to perform a nonportable pointer conversion (or when you pass an
  116. incompatible argument to an unprototyped function, although Jo's
  117. example code didn't do that), it's perfectly legal for a compiler
  118. to accept it, warn about it, or reject it.
  119.  
  120.                     Steve Summit
  121.                     scs@eskimo.com
  122. -- 
  123. The Communications Decency Act within the Telecommunications Act
  124. of 1996 (U.S.) is an annoying, threatening, abusive, indecent,
  125. and obscene piece of legislation which attempts to ban annoying,
  126. threatening, abusive, indecent, or obscene communication.
  127.